/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.channel;

import io.netty.buffer.ByteBuf;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;

import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;


/**
 * 处理或拦截 {@link Channel} inbound events and outbound operations 的 {@link ChannelHandler} 集合
 * {@link ChannelPipeline} 是一种
 * <a href="http://www.oracle.com/technetwork/java/interceptingfilter-142169.html">拦截过滤器模式</a>
 * 的高级形式, 以使用户完全控制, 一个事件如何被处理, 以及管道中 {@link ChannelHandler} 如何相互交互.
 *
 * <h3>创建管道(pipeline)</h3>
 * <p>
 * 每个 channel 有它自己的管道, 当 channel 被创建时, 将自动创建该管道.
 *
 * <h3>管道中事件如何流转</h3>
 * <p>
 * 下图描述了, 通常情况下, I/O 事件如何被 {@link ChannelPipeline} 中的 {@link ChannelHandler} 处理.
 * I/O 事件被 {@link ChannelInboundHandler} 或 {@link ChannelOutboundHandler} 处理,
 * 然后通过调用定义在 {@link ChannelHandlerContext} 中的事件传播方法
 * (如 {@link ChannelHandlerContext#fireChannelRead(Object)}, {@link ChannelHandlerContext#write(Object)}),
 * 将其转发到最近的 handler.
 *
 * <pre>
 *                                                 I/O Request
 *                                            via {@link Channel} or
 *                                        {@link ChannelHandlerContext}
 *                                                      |
 *  +---------------------------------------------------+---------------+
 *  |                           ChannelPipeline         |               |
 *  |                                                  \|/              |
 *  |    +---------------------+            +-----------+----------+    |
 *  |    | Inbound Handler  N  |            | Outbound Handler  1  |    |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |              /|\                                  |               |
 *  |               |                                  \|/              |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |    | Inbound Handler N-1 |            | Outbound Handler  2  |    |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |              /|\                                  .               |
 *  |               .                                   .               |
 *  | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
 *  |        [ method call]                       [method call]         |
 *  |               .                                   .               |
 *  |               .                                  \|/              |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |    | Inbound Handler  2  |            | Outbound Handler M-1 |    |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |              /|\                                  |               |
 *  |               |                                  \|/              |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |    | Inbound Handler  1  |            | Outbound Handler  M  |    |
 *  |    +----------+----------+            +-----------+----------+    |
 *  |              /|\                                  |               |
 *  +---------------+-----------------------------------+---------------+
 *                  |                                  \|/
 *  +---------------+-----------------------------------+---------------+
 *  |               |                                   |               |
 *  |       [ Socket.read() ]                    [ Socket.write() ]     |
 *  |                                                                   |
 *  |  Netty Internal I/O Threads (Transport Implementation)            |
 *  +-------------------------------------------------------------------+
 * </pre>
 * <p>
 * 如左图所示, inbound event 由 inbound handlers 按 自下向上 方向进行处理.
 * inbound handler 通常处理由图表底部的 I/O 线程产生的 inbound 数据.
 * 通常通过实际的输入操作, 如 {@link SocketChannel#read(ByteBuffer)}, 从远程 peer 读取 inbound 数据.
 * 如果 inbound 事件超过顶部 inbound handler, 那么它将被静默丢弃或(如果需要被您关注)被记录日志,
 *
 * <p>
 * 如右图所示, outbound event 由 outbound handlers 按 自上向下 方向进行处理.
 * outbound handler 通常产生或转换出站流量, 例如写请求.
 * 如果 outbound 事件超过低部 outbound handler, 那么它由与此 {@link Channel} 相关的 I/O 线程处理.
 * I/O 线程通常执行实际的输出操作, 如 {@link SocketChannel#write(ByteBuffer)}..
 * <p>
 * 例如, 让我们假设我们创建了如下管道:
 * <pre>
 * {@link ChannelPipeline} p = ...;
 * p.addLast("1", new InboundHandlerA());
 * p.addLast("2", new InboundHandlerB());
 * p.addLast("3", new OutboundHandlerA());
 * p.addLast("4", new OutboundHandlerB());
 * p.addLast("5", new InboundOutboundHandlerX());
 * </pre>
 * 上面的示例中,
 * 名称以 {@code Inbound} 开头的类表示它是一个 inbound handler.
 * 名称以 {@code outbound} 开头的类表示它是一个 outbound handler.
 * <p>
 * 在给出的示例配置中,
 * 当一个事件入站时, handler 评估顺序为 1, 2, 3, 4, 5
 * 当一个事件出站时, handler 评估顺序为 5, 4, 3, 2, 1
 * 在此原则上, {@link ChannelPipeline} 跳过特定 handler 的评估以缩短栈深:
 * <ul>
 * <li>3 和 4 没有实现 {@link ChannelInboundHandler}, 因此一个 inbound 事件的实际评估顺序为: 1, 2, 5 </li>
 * <li>1 和 2 没有实现 {@link ChannelOutboundHandler}, 因此一个 outbound 事件的实际评估顺序为: 5, 4, 3 </li>
 * <li>5 实现了 {@link ChannelInboundHandler} and {@link ChannelOutboundHandler},
 *     因此一个 inbound 和 outbound 事件的实际评估顺序对应地为: 125 和 543
 * </li>
 * </ul>
 *
 * <h3>转发事件到下一 handler</h3>
 * <p>
 * 正如图表所示, 一个 handler 必须调用 {@link ChannelHandlerContext} 中的事件传播方法来将事件转发到下一个 handler, 这些方法包括:
 * <ul>
 * <li>Inbound 事件传播方法:
 *     <ul>
 *     <li>{@link ChannelHandlerContext#fireChannelRegistered()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelActive()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelRead(Object)}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelReadComplete()}</li>
 *     <li>{@link ChannelHandlerContext#fireExceptionCaught(Throwable)}</li>
 *     <li>{@link ChannelHandlerContext#fireUserEventTriggered(Object)}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelWritabilityChanged()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelInactive()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelUnregistered()}</li>
 *     </ul>
 * </li>
 * <li>Outbound 事件传播方法:
 *     <ul>
 *     <li>{@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#write(Object, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#flush()}</li>
 *     <li>{@link ChannelHandlerContext#read()}</li>
 *     <li>{@link ChannelHandlerContext#disconnect(ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#close(ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#deregister(ChannelPromise)}</li>
 *     </ul>
 * </li>
 * </ul>
 * <p>
 * 以下示例说明了事件传播通常是如何完成的:
 *
 * <pre>
 * public class MyInboundHandler extends {@link ChannelInboundHandlerAdapter} {
 *     {@code @Override}
 *     public void channelActive({@link ChannelHandlerContext} ctx) {
 *         System.out.println("Connected!");
 *         ctx.fireChannelActive();
 *     }
 * }
 *
 * public class MyOutboundHandler extends {@link ChannelOutboundHandlerAdapter} {
 *     {@code @Override}
 *     public void close({@link ChannelHandlerContext} ctx, {@link ChannelPromise} promise) {
 *         System.out.println("Closing ..");
 *         ctx.close(promise);
 *     }
 * }
 * </pre>
 *
 * <h3>构建管道</h3>
 * <p>
 * 假定用户在管道中有一个或多个 {@link ChannelHandler} 来接收 I/O 事件(e.g. read)和请求 I/O 操作(e.g. write and close).
 * 例如, 典型服务在每个 channel 的管道中将有如下 handler, 其实际内容取决于协议和业务逻辑的复杂度和特性:
 *
 * <ol>
 * <li>协议解码器(Protocol Decoder) - 将二进制数据(e.g. {@link ByteBuf}) 转译成 Java 对象</li>
 * <li>协议编码器(Protocol Encoder) - 将 Java 对象转译成二进制数据</li>
 * <li>业务逻辑 Handler - 执行实际业务逻辑(e.g. 数据库访问)</li>
 * </ol>
 * <p>
 * 例如:
 *
 * <pre>
 * static final {@link EventExecutorGroup} group = new {@link DefaultEventExecutorGroup}(16);
 * ...
 *
 * {@link ChannelPipeline} pipeline = ch.pipeline();
 *
 * pipeline.addLast("decoder", new MyProtocolDecoder());
 * pipeline.addLast("encoder", new MyProtocolEncoder());
 *
 * // 告知 pipeline 在与 I/O 线程不同的线程中运行 MyBusinessLogicHandler 的 event handler 方法, 以使得该 I/O 线程不被耗时的任务阻塞.
 * // 如果你的业务逻辑完全是异步的, 或很快完成, 则无需指定一个 group.
 * pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
 * </pre>
 *
 * <h3>线程安全</h3>
 * <p>
 * 由于 {@link ChannelPipeline} 是线程安全的, 因此可以随时添加或删除 {@link ChannelHandler}.
 * 例如, 您可以在即将交换敏感信息时插入加密处理程序, 并在交换后将其删除.
 */
public interface ChannelPipeline
        extends ChannelInboundInvoker, ChannelOutboundInvoker,
        Iterable<Entry<String, ChannelHandler>> {

    /**
     * Inserts a {@link ChannelHandler} at the first position of this pipeline.
     *
     * @param name    the name of the handler to insert first
     * @param handler the handler to insert first
     * @throws IllegalArgumentException if there's an entry with the same name already in the pipeline
     * @throws NullPointerException     if the specified handler is {@code null}
     */
    ChannelPipeline addFirst(String name, ChannelHandler handler);

    /**
     * Inserts a {@link ChannelHandler} at the first position of this pipeline.
     *
     * @param group   the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}
     *                methods
     * @param name    the name of the handler to insert first
     * @param handler the handler to insert first
     * @throws IllegalArgumentException if there's an entry with the same name already in the pipeline
     * @throws NullPointerException     if the specified handler is {@code null}
     */
    ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);

    /**
     * Appends a {@link ChannelHandler} at the last position of this pipeline.
     *
     * @param name    the name of the handler to append
     * @param handler the handler to append
     * @throws IllegalArgumentException if there's an entry with the same name already in the pipeline
     * @throws NullPointerException     if the specified handler is {@code null}
     */
    ChannelPipeline addLast(String name, ChannelHandler handler);

    /**
     * 在此管道的最后一个位置追加一个 {@link ChannelHandler}
     *
     * @param group   将被用于执行 {@link ChannelHandler} 方法的 {@link EventExecutorGroup}
     * @param name    追加的 handler 的名称
     * @param handler 追加的 handler
     * @throws IllegalArgumentException if there's an entry with the same name already in the pipeline
     * @throws NullPointerException     if the specified handler is {@code null}
     */
    ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);

    /**
     * Inserts a {@link ChannelHandler} before an existing handler of this
     * pipeline.
     *
     * @param baseName the name of the existing handler
     * @param name     the name of the handler to insert before
     * @param handler  the handler to insert before
     * @throws NoSuchElementException   if there's no such entry with the specified {@code baseName}
     * @throws IllegalArgumentException if there's an entry with the same name already in the pipeline
     * @throws NullPointerException     if the specified baseName or handler is {@code null}
     */
    ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);

    /**
     * Inserts a {@link ChannelHandler} before an existing handler of this
     * pipeline.
     *
     * @param group    the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}
     *                 methods
     * @param baseName the name of the existing handler
     * @param name     the name of the handler to insert before
     * @param handler  the handler to insert before
     * @throws NoSuchElementException   if there's no such entry with the specified {@code baseName}
     * @throws IllegalArgumentException if there's an entry with the same name already in the pipeline
     * @throws NullPointerException     if the specified baseName or handler is {@code null}
     */
    ChannelPipeline addBefore(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);

    /**
     * Inserts a {@link ChannelHandler} after an existing handler of this
     * pipeline.
     *
     * @param baseName the name of the existing handler
     * @param name     the name of the handler to insert after
     * @param handler  the handler to insert after
     * @throws NoSuchElementException   if there's no such entry with the specified {@code baseName}
     * @throws IllegalArgumentException if there's an entry with the same name already in the pipeline
     * @throws NullPointerException     if the specified baseName or handler is {@code null}
     */
    ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);

    /**
     * Inserts a {@link ChannelHandler} after an existing handler of this
     * pipeline.
     *
     * @param group    the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}
     *                 methods
     * @param baseName the name of the existing handler
     * @param name     the name of the handler to insert after
     * @param handler  the handler to insert after
     * @throws NoSuchElementException   if there's no such entry with the specified {@code baseName}
     * @throws IllegalArgumentException if there's an entry with the same name already in the pipeline
     * @throws NullPointerException     if the specified baseName or handler is {@code null}
     */
    ChannelPipeline addAfter(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);

    /**
     * Inserts {@link ChannelHandler}s at the first position of this pipeline.
     *
     * @param handlers the handlers to insert first
     */
    ChannelPipeline addFirst(ChannelHandler... handlers);

    /**
     * Inserts {@link ChannelHandler}s at the first position of this pipeline.
     *
     * @param group    the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}s
     *                 methods.
     * @param handlers the handlers to insert first
     */
    ChannelPipeline addFirst(EventExecutorGroup group, ChannelHandler... handlers);

    /**
     * Inserts {@link ChannelHandler}s at the last position of this pipeline.
     *
     * @param handlers the handlers to insert last
     */
    ChannelPipeline addLast(ChannelHandler... handlers);

    /**
     * Inserts {@link ChannelHandler}s at the last position of this pipeline.
     *
     * @param group    the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}s
     *                 methods.
     * @param handlers the handlers to insert last
     */
    ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers);

    /**
     * Removes the specified {@link ChannelHandler} from this pipeline.
     *
     * @param handler the {@link ChannelHandler} to remove
     * @throws NoSuchElementException if there's no such handler in this pipeline
     * @throws NullPointerException   if the specified handler is {@code null}
     */
    ChannelPipeline remove(ChannelHandler handler);

    /**
     * Removes the {@link ChannelHandler} with the specified name from this pipeline.
     *
     * @param name the name under which the {@link ChannelHandler} was stored.
     * @return the removed handler
     * @throws NoSuchElementException if there's no such handler with the specified name in this pipeline
     * @throws NullPointerException   if the specified name is {@code null}
     */
    ChannelHandler remove(String name);

    /**
     * Removes the {@link ChannelHandler} of the specified type from this pipeline.
     *
     * @param <T>         the type of the handler
     * @param handlerType the type of the handler
     * @return the removed handler
     * @throws NoSuchElementException if there's no such handler of the specified type in this pipeline
     * @throws NullPointerException   if the specified handler type is {@code null}
     */
    <T extends ChannelHandler> T remove(Class<T> handlerType);

    /**
     * Removes the first {@link ChannelHandler} in this pipeline.
     *
     * @return the removed handler
     * @throws NoSuchElementException if this pipeline is empty
     */
    ChannelHandler removeFirst();

    /**
     * Removes the last {@link ChannelHandler} in this pipeline.
     *
     * @return the removed handler
     * @throws NoSuchElementException if this pipeline is empty
     */
    ChannelHandler removeLast();

    /**
     * Replaces the specified {@link ChannelHandler} with a new handler in this pipeline.
     *
     * @param oldHandler the {@link ChannelHandler} to be replaced
     * @param newName    the name under which the replacement should be added
     * @param newHandler the {@link ChannelHandler} which is used as replacement
     * @return itself
     * @throws NoSuchElementException   if the specified old handler does not exist in this pipeline
     * @throws IllegalArgumentException if a handler with the specified new name already exists in this
     *                                  pipeline, except for the handler to be replaced
     * @throws NullPointerException     if the specified old handler or new handler is
     *                                  {@code null}
     */
    ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);

    /**
     * Replaces the {@link ChannelHandler} of the specified name with a new handler in this pipeline.
     *
     * @param oldName    the name of the {@link ChannelHandler} to be replaced
     * @param newName    the name under which the replacement should be added
     * @param newHandler the {@link ChannelHandler} which is used as replacement
     * @return the removed handler
     * @throws NoSuchElementException   if the handler with the specified old name does not exist in this pipeline
     * @throws IllegalArgumentException if a handler with the specified new name already exists in this
     *                                  pipeline, except for the handler to be replaced
     * @throws NullPointerException     if the specified old handler or new handler is
     *                                  {@code null}
     */
    ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);

    /**
     * Replaces the {@link ChannelHandler} of the specified type with a new handler in this pipeline.
     *
     * @param oldHandlerType the type of the handler to be removed
     * @param newName        the name under which the replacement should be added
     * @param newHandler     the {@link ChannelHandler} which is used as replacement
     * @return the removed handler
     * @throws NoSuchElementException   if the handler of the specified old handler type does not exist
     *                                  in this pipeline
     * @throws IllegalArgumentException if a handler with the specified new name already exists in this
     *                                  pipeline, except for the handler to be replaced
     * @throws NullPointerException     if the specified old handler or new handler is
     *                                  {@code null}
     */
    <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName,
                                         ChannelHandler newHandler);

    /**
     * Returns the first {@link ChannelHandler} in this pipeline.
     *
     * @return the first handler.  {@code null} if this pipeline is empty.
     */
    ChannelHandler first();

    /**
     * Returns the context of the first {@link ChannelHandler} in this pipeline.
     *
     * @return the context of the first handler.  {@code null} if this pipeline is empty.
     */
    ChannelHandlerContext firstContext();

    /**
     * Returns the last {@link ChannelHandler} in this pipeline.
     *
     * @return the last handler.  {@code null} if this pipeline is empty.
     */
    ChannelHandler last();

    /**
     * Returns the context of the last {@link ChannelHandler} in this pipeline.
     *
     * @return the context of the last handler.  {@code null} if this pipeline is empty.
     */
    ChannelHandlerContext lastContext();

    /**
     * Returns the {@link ChannelHandler} with the specified name in this
     * pipeline.
     *
     * @return the handler with the specified name.
     * {@code null} if there's no such handler in this pipeline.
     */
    ChannelHandler get(String name);

    /**
     * Returns the {@link ChannelHandler} of the specified type in this
     * pipeline.
     *
     * @return the handler of the specified handler type.
     * {@code null} if there's no such handler in this pipeline.
     */
    <T extends ChannelHandler> T get(Class<T> handlerType);

    /**
     * 返回该 pipeline 中指定 {@link ChannelHandler} 的 context 对象.
     *
     * @return the context object of the specified handler.
     * {@code null} if there's no such handler in this pipeline.
     */
    ChannelHandlerContext context(ChannelHandler handler);

    /**
     * Returns the context object of the {@link ChannelHandler} with the
     * specified name in this pipeline.
     *
     * @return the context object of the handler with the specified name.
     * {@code null} if there's no such handler in this pipeline.
     */
    ChannelHandlerContext context(String name);

    /**
     * Returns the context object of the {@link ChannelHandler} of the
     * specified type in this pipeline.
     *
     * @return the context object of the handler of the specified type.
     * {@code null} if there's no such handler in this pipeline.
     */
    ChannelHandlerContext context(Class<? extends ChannelHandler> handlerType);

    /**
     * Returns the {@link Channel} that this pipeline is attached to.
     *
     * @return the channel. {@code null} if this pipeline is not attached yet.
     */
    Channel channel();

    /**
     * Returns the {@link List} of the handler names.
     */
    List<String> names();

    /**
     * Converts this pipeline into an ordered {@link Map} whose keys are
     * handler names and whose values are handlers.
     */
    Map<String, ChannelHandler> toMap();

    @Override
    ChannelPipeline fireChannelRegistered();

    @Override
    ChannelPipeline fireChannelUnregistered();

    @Override
    ChannelPipeline fireChannelActive();

    @Override
    ChannelPipeline fireChannelInactive();

    @Override
    ChannelPipeline fireExceptionCaught(Throwable cause);

    @Override
    ChannelPipeline fireUserEventTriggered(Object event);

    @Override
    ChannelPipeline fireChannelRead(Object msg);

    @Override
    ChannelPipeline fireChannelReadComplete();

    @Override
    ChannelPipeline fireChannelWritabilityChanged();

    @Override
    ChannelPipeline flush();
}
